#include "interaction.hpp"
#include "light.hpp"
#include "material.hpp"
#include "shape.hpp"
namespace chen {

Spectrum SurfInteract::Le () const {
    assert(hit != nullptr);
    if(chen::hasFlag(((Shape*)hit)->flags, FSHAPE_AREALIGHT)) {
        assert(((const Shape*)hit)->arealight != nullptr);
        return ((const Shape*)hit)->arealight->Lo(*this, -wh, uv);
    }
    return Spectrum(0);
}

bool SurfInteract::applyMaterial (bool dir) {
    return ((const Shape*)hit)->material->apply(this, dir);
}

Interact Transform::operator () (const Interact & in) const {
    Point3 np;
    Vector3 e;
    np = (*this)(in.p, in.p_err, &e);
    return Interact(
        np,
        e,
        (*this)(in.wh),
        (*this)(in.ng),
        (const Object*)in.hit,
        in.flipped
    );
}
Interact Transform::reversed (const Interact & in) const {
    Point3 np;
    Vector3 e;
    np = reversed(in.p, in.p_err, &e);
    return Interact(
        np,
        e,
        reversed(in.wh),
        reversed(in.ng),
        (const Object*)in.hit,
        in.flipped
    );
}

SurfInteract Transform::operator () (const SurfInteract & si) const {
    Point3 np;
    Vector3 e;
    np = (*this)(si.p, si.p_err, &e);
    return SurfInteract(
        np,
        e,
        (*this)(si.wh),
        (*this)(si.ng),
        (const Shape*)si.hit,
        si.flipped,
        (*this)(si.ngy),
        si.uv,
        (*this)(si.dpdu),
        (*this)(si.dpdv),
        (*this)(si.dndu),
        (*this)(si.dndv)
    );
}
SurfInteract Transform::reversed (const SurfInteract & si) const {
    Point3 np;
    Vector3 e;
    np = reversed(si.p, si.p_err, &e);
    return SurfInteract(
        np,
        e,
        reversed(si.wh),
        reversed(si.ng),
        (const Shape*)si.hit,
        si.flipped,
        reversed(si.ngy),
        si.uv,
        reversed(si.dpdu),
        reversed(si.dpdv),
        reversed(si.dndu),
        reversed(si.dndv)
    );
}

}